Example of Jupyter/Ginga widget

This is an example of creating a Jupyter data viewer widget using a Jupyter image widget and the Ginga viewer toolkit.

NOTE: To use these examples, you need to install the ipyevents package:

$ pip install ipyevents

$ jupyter nbextension enable --py --sys-prefix ipyevents


In [9]:
# create a Jupyter image that will be our display surface
# format can be 'jpeg' or 'png'; specify width and height to set viewer size
# PNG will be a little clearer, especially with overlaid graphics, but
# JPEG is faster to update
import ipywidgets as widgets
jup_img = widgets.Image(format='jpeg', width=500, height=500)

In [10]:
# Boilerplate to create a Ginga viewer connected to this widget
# this could be simplified, or hidden behind a class or convenience 
# method
# NOTE: you don't have to specify a log file--and if you are not interested
# in the log just specify null=True for a null logger
# level=10 will give you the most debugging information
from ginga.misc.log import get_logger
logger = get_logger("my viewer", log_stderr=False, log_file='/tmp/ginga.log', level=40)

from ginga.web.jupyterw.ImageViewJpw import EnhancedCanvasView
v1 = EnhancedCanvasView(logger=logger)
# set our linkage between the jupyter widget at ginga
v1.set_widget(jup_img)

# enable all possible keyboard and pointer operations
bd = v1.get_bindings()
bd.enable_all(True)

In [11]:
coordinates = widgets.HTML('<h3>coordinates show up here</h3>')

# callback to display position in RA/DEC deg
def mouse_move(viewer, button, data_x, data_y, w):
    image = viewer.get_image()
    if image is not None:
        ra, dec = image.pixtoradec(data_x, data_y)
        w.value = "cursor at %f, %f" % (ra, dec)

v1.add_callback('cursor-changed', mouse_move, coordinates)

In [12]:
%%javascript
/* some magic to keep the cell contents from scrolling
   (when we embed the viewer)
 */
IPython.OutputArea.prototype._should_scroll = function(lines) {
    return false;
}



In [13]:
# embed the viewer here

widgets.VBox([jup_img, coordinates])



In [14]:
# Load a FITS file.  You should see the embedded image update.
v1.load_fits("/home/eric/testdata/SPCAM/SUPA01118766.fits")


WARNING: FITSFixedWarning: RADECSYS= 'FK5 ' 
the RADECSYS keyword is deprecated, use RADESYSa. [astropy.wcs.wcs]
WARNING: FITSFixedWarning: 'unitfix' made the change 'Changed units: 'degree' -> 'deg', 'degree' -> 'deg''. [astropy.wcs.wcs]

You can now do nearly everything that can be done with a regular "pg" type ginga web widget. See http://ginga.readthedocs.io/en/latest/quickref.html for default key and button/pointer bindings.

See https://github.com/ejeschke/ginga/blob/master/ginga/examples/jupyter-notebook/ginga_ipython_demo.ipynb for the kinds of things you can do with the embedded viewer including graphics overplotting, etc.


In [15]:
# grab a screenshot.
v1.show()


Out[15]:

In [16]:
# add a canvas to the image and set the draw type
canvas = v1.add_canvas()
canvas.set_drawtype('ellipse', color='orange', fill=True, fillcolor='cyan', fillalpha=0.3)

Now press and release space bar in the viewer and draw the shape. Or you can use the right mouse button.


In [17]:
v1.show()


Out[17]:

In [8]:
# put the canvas in edit mode
canvas.enable_edit(True)
canvas.set_draw_mode('edit')

Now you can click on the object to select it and edit it. Editing control points should appear:

  • orange: stretch or shrink dimension(s)
  • green: scale object while keeping aspect
  • blue: rotate object
  • red: move object You can also move objects simply by dragging anywhere in the bounding box if they are selected.

In [18]:
canvas.get_objects()


Out[18]:
[<ginga.canvas.types.basic.Ellipse at 0x7fe9a7314400>]

In [19]:
# let's get the object that we drew--what is it's location?
ell = canvas.get_objects()[0]
ell.x, ell.y


Out[19]:
(1433.5, 1405.0)

In [20]:
ell.xradius, ell.yradius


Out[20]:
(14.5, 40.75)

In [21]:
# delete everything on the canvas that we drew
canvas.delete_all_objects()

In [ ]: